﻿using System;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace QAQ
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private bool ImClient = false;
        private bool ClientSlaveIdSet;
        private bool findForward;

        private bool roomNameV;
        private string roomName;

        private ImgProc mImgProc = null;
        private GameCtrl mGameCtrl = null;
        private IntPtr mProcessHandle = IntPtr.Zero;
        private Collection<IntPtr> cIntPtrs;


        public static bool mBadass = false;
        private int GG3be0Count;
        public static bool GG3be0;
        private int UknownWait;
        private const int retryTime = 10;
        private int ClientRetry;
        //TODO:SECondary Queue
        public static bool secondaryV;
        public static int secondaryId;
        public static string secondaryPW;
        public static bool GoNow;

        private bool mIsBackgroundEnabled=false;

        private int GNtime;

        private bool Enable = false;

        private void Form1_Load(object sender, EventArgs e)
        {
            mImgProc = new ImgProc();
            mGameCtrl = new GameCtrl();

            ClientSlaveIdSet = false;
            findForward = false;
            secondaryV = false;
            GG3be0 = false;
            GG3be0Count = 0;
            GoNow = false;
            ClientRetry = 0;
            UknownWait = 0;

            //Gma.UserActivityMonitor.HookManager.KeyDown += OnKeyDownEventListener;
            propertyGrid1.SelectedObject = this;
            this.timer1.Start();
        }

        private void OnKeyDownEventListener(object o, KeyEventArgs e)
        {
            switch (e.KeyData)
            {
                case Keys.End:
                    this.checkBox1.Checked = false;
                    //this.Enable = false;
                    break;
            }
        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            mProcessHandle = User32.FindWindow("D3D Window", "GrandChase Eternal v1.05.62 (20090120)");

            if (mProcessHandle != IntPtr.Zero)
            {
                mGameCtrl.SetProcesshandle(mProcessHandle);

                if (cIntPtrs != null)
                {
                    cIntPtrs.Clear();
                }
                else
                {
                    cIntPtrs = new Collection<IntPtr>();
                }


                var temp = User32.FindWindowEx(mProcessHandle, IntPtr.Zero, "Edit", string.Empty);
                while (temp != IntPtr.Zero)
                {
                    cIntPtrs.Add(temp);
                    temp = User32.FindWindowEx(mProcessHandle, temp, "Edit", string.Empty);
                }

                this.timer1.Stop();
                this.timer2.Start();

                label1.Text = "Detected";
            }
            else
            {
                if (cIntPtrs != null)
                {
                    cIntPtrs.Clear();
                    cIntPtrs = null;
                }
                label1.Text = "I am linstening...";
            }
        }

        private void fsm_Server()
        {
            if (mImgProc.state == ImgProc.STA_Unknown)
            {
                UknownWait++;
                if (UknownWait > 10)
                {
                    mGameCtrl.Action(GameCtrl.act.MouseGoAway);
           //         mGameCtrl.Action(GameCtrl.act.Enter);
                    mGameCtrl.Action(GameCtrl.act.Exit);
                    mGameCtrl.Action(GameCtrl.act.GoCompete);
                    UknownWait = 0;
                }
            }
            else
            {
                UknownWait = 0;
                switch (mImgProc.mState[mImgProc.state].staenum)
                {
                    case StateEnum.isCompeteDone:
                        mGameCtrl.Action(GameCtrl.act.Exit);
                        if (true == secondaryV)
                        {
                            mGCPacketSocServer.clear();
                            mGCPacketSocServer.id = secondaryId;
                            mGCPacketSocServer.pw = secondaryPW;
                            mGCPacketSocServer.valid = true;
                            mGCPacketSocServer.sent = false;
                        }
                        break;
                    case StateEnum.isGetAward:
                        mGameCtrl.Action(GameCtrl.act.Enter);
                        break;
                    case StateEnum.isP2Ready:
                        //@@DO ack
                        //TODO:sync to client and prepare to f9
                        mGameCtrl.Action(GameCtrl.act.ReadyToGo);
                        //DO NOT CLEAR PACKET HERE!
                        //mGCPacketSocServer.clear();
                        break;
                    case StateEnum.isInLobby:
                        mGCPacketSocServer.clear();
                        mGameCtrl.Action(GameCtrl.act.CreateRoom);
                        break;
                    case StateEnum.isServerReady:
                    case StateEnum.isInRoom:
                        if (GG3be0Count >= 3)
                        {
                            GG3be0Count = 0;
                            GG3be0 = true;
                            mGCPacketSocServer.clear();
                            mGameCtrl.Action(GameCtrl.act.LeaveRoom);
                            mImgProc.mTargetRoomId = -5;
                            break;
                        }
                        if (true == mBadass)
                        {
                            mGameCtrl.Action(GameCtrl.act.ConfigRoom);
                            GG3be0Count++;
                        }
                        //TODO:Add Ack to cancle sending for the earth
                        mGCPacketSocServer.id = mImgProc.mCurrentRoomId;
                        if (mGCPacketSocServer.pw == string.Empty)
                        {
                            mGCPacketSocServer.clear();
                            mGameCtrl.Action(GameCtrl.act.LeaveRoom);
                            break;
                        }
                        mGCPacketSocServer.valid = true;
                        mGCPacketSocServer.sent = false;

                        break;
                    case StateEnum.isPromptExit:
                        mGameCtrl.Action(GameCtrl.act.PromptYes);
                        break;
                    case StateEnum.isConfiguring:
                        //mGameCtrl.CreateRoomFocusPWForm(mProcessHandle);
                        if (mGCPacketSocServer.pw == string.Empty)
                        {
                            mGCPacketSocServer.GenerateKey();
                        }
                        if (true == roomNameV)
                        {
                            mGameCtrl.SetControlText(cIntPtrs[ControlIndex.room.RoomName], roomName);
                        }

                        mGameCtrl.SetControlText(cIntPtrs[ControlIndex.room.Password],
                            mGCPacketSocServer.pw);
                        mGameCtrl.Action(GameCtrl.act.Enter);
                        mBadass = false;
                        break;
                    case StateEnum.isDefaultSetting:
                        mGameCtrl.Action(GameCtrl.act.ChangeCompeteType);
                        break;

                    case StateEnum.isCreatingRoom:
                        if (mGCPacketSocServer.pw == string.Empty)
                        {
                            mGCPacketSocServer.GenerateKey();
                        }
                        if (true == roomNameV)
                        {
                            mGameCtrl.SetControlText(cIntPtrs[ControlIndex.lobby.RoomName], roomName);
                        }

                        mGameCtrl.SetControlText(cIntPtrs[ControlIndex.lobby.Password], mGCPacketSocServer.pw);
                        mGameCtrl.Action(GameCtrl.act.Enter);
                        break;
                    case StateEnum.isEquip:
                        mGameCtrl.Action(GameCtrl.act.GoCompete);
                        break;
                    case StateEnum.isLoading:
                        mGCPacketSocServer.clear();
                        break;
                    default:
                        break;
                }
            }
        }

        private void fsm_Client()
        {
            if (mImgProc.state == ImgProc.STA_Unknown)
            {
                UknownWait++;
                if (UknownWait > 10)
                {
                    mGameCtrl.Action(GameCtrl.act.MouseGoAway);
                    //mGameCtrl.Action(GameCtrl.act.Enter);
                    UknownWait = 0;
                }
            }
            else
            {
                UknownWait = 0;
                switch (mImgProc.mState[mImgProc.state].staenum)
                {
                    case StateEnum.isGetAward:
                        mGameCtrl.Action(GameCtrl.act.Enter);
                        break;
                    case StateEnum.isInGame:
                        mGameCtrl.Action(GameCtrl.act.Exit);
                        break;
                    case StateEnum.isInLobby:
                        if (false == ClientSlaveIdSet ||
                            ClientRetry >= retryTime)
                        {
                            ClientSlaveIdSet = true;
                            ClientRetry = 0;
                            mGCPacketSocClient.clear();
                            break;
                        }
                        if (false == mGCPacketSocClient.isValid())
                        {
                            mImgProc.mTargetRoomId = -4;
                            break;
                        }

                        if (true == mImgProc.mVTargetRoomIndex)
                        {
                            mGameCtrl.EnterRoom(mImgProc.mTargetRoomIndex);
                        }
                        else
                        {
                            //find room
                            if (true == mImgProc.isEndOfPage)
                            {
                                findForward = !findForward;
                                ClientRetry++;
                            }
                            if (true == findForward)
                            {
                                mGameCtrl.Action(GameCtrl.act.NxtPage);
                            }
                            else
                            {
                                mGameCtrl.Action(GameCtrl.act.PrePage);
                            }
                        }
                        break;
                    case StateEnum.isP2Ready:
                        //System.Threading.Thread.Sleep(193);
                        //mGameCtrl.LeaveRoom(mProcessHandle);
                        //System.Threading.Thread.Sleep(GNtime);

                        //GoNow = true;
                        //findForward = false;
                        //ClientSlaveIdSet = false;
                        //mImgProc.mTargetRoomId = -2;
                        break;
                    case StateEnum.isDefaultSetting:
                    case StateEnum.isServerReady:
                    case StateEnum.isInRoom:
                        //check current room is the target or not
                        if (mImgProc.mCurrentRoomId == mImgProc.mTargetRoomId)
                        {
                            mGameCtrl.Action(GameCtrl.act.ReadyToGo);
                        }
                        else
                        {
                            mGameCtrl.Action(GameCtrl.act.LeaveRoom);
                        }
                        ClientRetry = 0;

                        break;
                    case StateEnum.isPromptExit:
                        mGameCtrl.Action(GameCtrl.act.PromptYes);
                        findForward = false;
                        ClientSlaveIdSet = false;
                        mGCPacketSocClient.clear();
                        mImgProc.mTargetRoomId = -2;
                        break;
                    case StateEnum.isPromptPassword:
                        if (false == mGCPacketSocClient.isValid())
                        {
                            mGCPacketSocClient.clear();
                            mGameCtrl.Action(GameCtrl.act.Exit);
                            break;
                        }

                        mGameCtrl.SetControlText(cIntPtrs[ControlIndex.SlaveEnterPassword],
                            mGCPacketSocClient.pw);
                        mGameCtrl.Action(GameCtrl.act.SlaveEnterPass);

                        this.textBox2.Text = mGCPacketSocClient.pw;
                        break;
                    case StateEnum.isWtfError:
                        mGameCtrl.Action(GameCtrl.act.Enter);
                        break;
                    case StateEnum.isWrongPW:
                        SocClient.badass = true;
                        ClientRetry++;
                        mGCPacketSocClient.clear();
                        mGameCtrl.Action(GameCtrl.act.Enter);
                        break;

                    default:
                        break;
                }
            }
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            StringBuilder TittleStringBuilder = new StringBuilder();

            try
            {
                mImgProc.fetchImg(mProcessHandle);
            }
            catch (Exception exc)
            {
                this.timer2.Enabled = false;
                this.timer1.Enabled = true;
                return;
            }

            //@@todo:depricated
            try
            {
                if (true == ImClient)
                {
                    this.textBox1.Text = mImgProc.mTargetRoomId.ToString();
                    this.textBox2.Text = mGCPacketSocClient.pw;
                    if (true == mGCPacketSocClient.isValid())
                    {
                        if (true == ClientStarted)
                        {
                            mImgProc.mTargetRoomId = mGCPacketSocClient.id;
                        }
                    }
                    else
                    {
                        mImgProc.mTargetRoomId = -4;
                        TittleStringBuilder.Append("Waiting ");
                    }
                }
                else
                {
                }
            }
            catch (Exception exc)
            {
                if (true == ImClient)
                {
                    this.label3.Text = exc.Message.ToString();
                    return;
                }
            }

            mImgProc.Update();

            /*
            if (false == ImClient && true == ServerStarted)
            {
                mGCPacketSocServer.SetId(mImgProc.mCurrentRoomId);
                mGCPacketSocServer.pw = mGCPacketSocServer.GenerateKey(mImgProc.mCurrentRoomId);
            }*/


            if (false == ClientStarted && false == ServerStarted)
            {
                return;
            }

            //TODO:.bad .fix polling PostMessage
            if (mProcessHandle != User32.GetForegroundWindow())
            {
                //is in background
                mIsBackgroundEnabled = false;
                User32.PostMessage(mProcessHandle, WMsg.WM_ACTIVATEAPP, (IntPtr)1, IntPtr.Zero);
            }
             
             


            ////show state
            if (mImgProc.state == ImgProc.STA_Unknown)
            {
                TittleStringBuilder.Append("Unknown");
            }
            else
            {
                TittleStringBuilder.Append(mImgProc.mState[mImgProc.state].staname);
            }
            this.Text = TittleStringBuilder.ToString();
            switch (mGameCtrl.GetControlText(cIntPtrs[ControlIndex.room.Chat])
                    .ToLower())
            {
                case "stop":
                    this.checkBox1.Checked = false;
                    mGameCtrl.SetControlText(cIntPtrs[ControlIndex.room.Chat],
                        string.Empty);
                    break;
                case "start":
                    this.checkBox1.Checked = true;
                    mGameCtrl.SetControlText(cIntPtrs[ControlIndex.room.Chat],
                        string.Empty);
                    break;
                default:
                    break;
            }

            switch (mGameCtrl.GetControlText(cIntPtrs[ControlIndex.lobby.Chat]).ToLower())
            {
                case "start":
                    mGameCtrl.SetControlText(cIntPtrs[ControlIndex.lobby.Chat], string.Empty);
                    this.checkBox1.Checked = true;
                    break;
                case "stop":
                    mGameCtrl.SetControlText(cIntPtrs[ControlIndex.lobby.Chat], string.Empty);
                    this.checkBox1.Checked = false;
                    return;
                default:
                    if (false == Enable)
                    {
                        return;
                    }
                    break;
            }

            //fsm
            if (true == ImClient)
            {
                fsm_Client();
            }
            else
            {
                fsm_Server();
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            Enable = this.checkBox1.Checked;
        }


        private SocServer mSocServer;
        private GCPacket mGCPacketSocServer;
        private bool ServerStarted = false;

        private void button1_Click(object sender, EventArgs e)
        {
            this.ImClient = false;
            if (ServerStarted == false)
            {
                mGCPacketSocServer = new GCPacket();
                mSocServer = new SocServer(mGCPacketSocServer, Convert.ToInt32(this.textBox4.Text));

                ServerStarted = true;
            }
            mGCPacketSocServer.id = mImgProc.mCurrentRoomId;
            mGCPacketSocServer.GenerateKey();
        }

        private bool ClientStarted = false;
        private SocClient mSocClient;
        private GCPacket mGCPacketSocClient;

        private void button2_Click(object sender, EventArgs e)
        {
            this.ImClient = true;
            if (ClientStarted == false)
            {
                ClientStarted = true;
                mGCPacketSocClient = new GCPacket();
                mSocClient = new SocClient(mGCPacketSocClient, this.textBox3.Text, Convert.ToInt32(this.textBox4.Text));
            }
            mGCPacketSocClient.clear();
            this.textBox1.Text = mGCPacketSocClient.id.ToString();
            this.textBox2.Text = mGCPacketSocClient.pw;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (mSocServer != null)
            {
                mSocServer.Dispose();
            }
            if (mSocClient != null)
            {
                mSocClient.Dispose();
            }
        }

        private void textBox5_TextChanged(object sender, EventArgs e)
        {

        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            secondaryId = Convert.ToInt32(this.textBox6.Text);
            secondaryPW = this.textBox7.Text;
            secondaryV = this.checkBox2.Checked;
        }

        private void textBox8_TextChanged(object sender, EventArgs e)
        {
            try
            {
                GNtime = Convert.ToInt32(this.textBox8.Text);
                this.textBox8.BackColor = Color.White;
            }
            catch (Exception exc)
            {
                this.textBox8.BackColor = Color.Red;
                GNtime = 60;
            }
        }

        private class ControlIndex
        {
            public class lobby
            {
                public const int Chat = 0;
                public const int RoomName = 42;
                public const int Password = 43;
            };
            public class room
            {
                public const int Chat = 12;
                public const int RoomName = 44;
                public const int Password = 45;
            };
            public const int SlaveEnterPassword = 47;
        }

        private void textBox9_TextChanged(object sender, EventArgs e)
        {
            try
            {
                roomName = this.textBox9.Text;
                this.textBox8.BackColor = Color.White;
            }
            catch (Exception exc)
            {
                this.textBox9.BackColor = Color.Red;
                roomName = string.Empty;
            }
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            this.roomNameV = this.checkBox3.Checked;
            this.roomName = this.textBox9.Text;
        }
    }
}